// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;
using System;
using System.IO;
using EpicGames.Core;
using System.Collections.Generic;
using UnrealBuildBase;
using Microsoft.Extensions.Logging;

/* LyraGameTarget类，继承自TargetRules，用于定义Lyra游戏项目的构建目标规则 */
public class LyraGameTarget : TargetRules
{
	/* 构造函数，接收TargetInfo参数 */
	public LyraGameTarget(TargetInfo Target) : base(Target)
	{
		Type = TargetType.Game; // 设置目标类型为游戏

		ExtraModuleNames.AddRange(new string[] { "LyraGame" }); // 添加额外的模块名称

		LyraGameTarget.ApplySharedLyraTargetSettings(this); // 应用共享的Lyra目标设置
	}

	private static bool bHasWarnedAboutShared = false; // 静态标志，用于记录是否已警告过共享构建环境

	/* 应用共享的Lyra目标设置的静态方法 */
	internal static void ApplySharedLyraTargetSettings(TargetRules Target)
	{
		ILogger Logger = Target.Logger; // 获取日志记录器
		
		Target.DefaultBuildSettings = BuildSettingsVersion.V5; // 设置默认构建设置版本为V5
		Target.IncludeOrderVersion = EngineIncludeOrderVersion.Latest; // 设置包含顺序版本为最新

		bool bIsTest = Target.Configuration == UnrealTargetConfiguration.Test; // 检查是否为测试配置
		bool bIsShipping = Target.Configuration == UnrealTargetConfiguration.Shipping; // 检查是否为发布配置
		bool bIsDedicatedServer = Target.Type == TargetType.Server; // 检查是否为专用服务器
		if (Target.BuildEnvironment == TargetBuildEnvironment.Unique) // 如果构建环境是唯一的
		{
			Target.CppCompileWarningSettings.ShadowVariableWarningLevel = WarningLevel.Error; // 设置阴影变量警告级别为错误

			Target.bUseLoggingInShipping = true; // 在发布版本中启用日志记录
			Target.bTrackRHIResourceInfoForTest = true; // 为测试跟踪RHI资源信息

			if (bIsShipping && !bIsDedicatedServer) // 如果是发布版本且不是专用服务器
			{
				// 确保验证HTTPS流量的证书
				Target.bDisableUnverifiedCertificates = true; // 禁用未验证的证书

				// 取消注释这些行以锁定命令行处理
				// 这将只允许解析指定的命令行参数
				//Target.GlobalDefinitions.Add("UE_COMMAND_LINE_USES_ALLOW_LIST=1");
				//Target.GlobalDefinitions.Add("UE_OVERRIDE_COMMAND_LINE_ALLOW_LIST=\"-space -separated -list -of -commands\"");

				// 取消注释此行以过滤掉您不希望进入日志文件的敏感命令行参数
				//Target.GlobalDefinitions.Add("FILTER_COMMANDLINE_LOGGING=\"-some_connection_id -some_other_arg\"");
			}

			if (bIsShipping || bIsTest) // 如果是发布或测试配置
			{
				// 禁用读取生成的/非UFS ini文件
				Target.bAllowGeneratedIniWhenCooked = false; // 禁止在打包后使用生成的ini
				Target.bAllowNonUFSIniWhenCooked = false; // 禁止在打包后使用非UFS ini
			}

			if (Target.Type != TargetType.Editor) // 如果目标类型不是编辑器
			{
				// 我们在运行时不使用路径追踪器，仅用于美观截图，且此DLL相当大
				Target.DisablePlugins.Add("OpenImageDenoise"); // 禁用OpenImageDenoise插件

				// 减少AssetRegistry常驻数据的内存使用，但增加更多CPU时间昂贵的查询
				Target.GlobalDefinitions.Add("UE_ASSETREGISTRY_INDIRECT_ASSETDATA_POINTERS=1"); // 添加全局定义
			}

			LyraGameTarget.ConfigureGameFeaturePlugins(Target); // 配置游戏功能插件
		}
		else // 如果构建环境不是唯一的
		{
			// !!!!!!!!!!!! 警告 !!!!!!!!!!!!!
			// 此处的任何更改都不能影响PCH生成，否则目标需要设置为TargetBuildEnvironment.Unique

			// 这仅在编辑器或唯一构建环境中工作
			if (Target.Type == TargetType.Editor) // 如果目标类型是编辑器
			{
				LyraGameTarget.ConfigureGameFeaturePlugins(Target); // 配置游戏功能插件
			}
			else // 否则
			{
				// 共享单块构建无法启用/禁用插件或更改任何选项，因为它尝试重用已安装的引擎二进制文件
				if (!bHasWarnedAboutShared) // 如果尚未警告过共享构建
				{
					bHasWarnedAboutShared = true; // 设置警告标志为true
					Logger.LogWarning("LyraGameEOS and dynamic target options are disabled when packaging from an installed version of the engine"); // 记录警告
				}
			}
		}
	}

	/* 静态方法，决定是否启用所有游戏功能插件 */
	static public bool ShouldEnableAllGameFeaturePlugins(TargetRules Target)
	{
		if (Target.Type == TargetType.Editor) // 如果目标类型是编辑器
		{
			// 如果返回true，编辑器构建将构建所有游戏功能插件，但可能不会加载它们。
			// 这是为了您可以在编辑器中启用插件而无需编译代码。
			// return true;
		}

		bool bIsBuildMachine = (Environment.GetEnvironmentVariable("IsBuildMachine") == "1"); // 检查是否为构建机器
		if (bIsBuildMachine) // 如果是构建机器
		{
			// 这可以用于为构建机器启用所有插件
			// return true;
		}

		// 默认情况下，使用编辑器插件浏览器中设置的默认插件规则
		// 这很重要，因为对于启动器安装的引擎版本，此代码可能根本不会运行
		return false; // 返回false
	}

	private static Dictionary<string, JsonObject> AllPluginRootJsonObjectsByName = new Dictionary<string, JsonObject>(); // 缓存插件JSON对象的字典

	/* 配置我们想要启用的游戏功能插件的静态方法 */
	// 这是一个相当简单的实现，但您可能会根据当前分支的目标发布版本构建不同的插件，例如，在主分支中启用进行中的功能，但在当前发布分支中禁用它们。
	static public void ConfigureGameFeaturePlugins(TargetRules Target)
	{
		ILogger Logger = Target.Logger; // 获取日志记录器
		Log.TraceInformationOnce("Compiling GameFeaturePlugins in branch {0}", Target.Version.BranchName); // 记录一次跟踪信息

		bool bBuildAllGameFeaturePlugins = ShouldEnableAllGameFeaturePlugins(Target); // 决定是否构建所有游戏功能插件

		// 加载所有游戏功能.uplugin描述符
		List<FileReference> CombinedPluginList = new List<FileReference>(); // 创建插件文件引用列表

		List<DirectoryReference> GameFeaturePluginRoots = Unreal.GetExtensionDirs(Target.ProjectFile.Directory, Path.Combine("Plugins", "GameFeatures")); // 获取游戏功能插件根目录
		foreach (DirectoryReference SearchDir in GameFeaturePluginRoots) // 遍历每个搜索目录
		{
			CombinedPluginList.AddRange(PluginsBase.EnumeratePlugins(SearchDir)); // 枚举插件并添加到列表
		}

		if (CombinedPluginList.Count > 0) // 如果插件列表不为空
		{
			Dictionary<string, List<string>> AllPluginReferencesByName = new Dictionary<string, List<string>>(); // 创建插件引用字典

			foreach (FileReference PluginFile in CombinedPluginList) // 遍历每个插件文件
			{
				if (PluginFile != null && FileReference.Exists(PluginFile)) // 如果插件文件存在
				{
					bool bEnabled = false; // 初始化启用标志
					bool bForceDisabled = false; // 初始化强制禁用标志
					try
					{
						JsonObject RawObject; // 声明JSON对象
						if (!AllPluginRootJsonObjectsByName.TryGetValue(PluginFile.GetFileNameWithoutExtension(), out RawObject)) // 如果缓存中没有该插件的JSON对象
						{
							RawObject = JsonObject.Read(PluginFile); // 读取插件文件
							AllPluginRootJsonObjectsByName.Add(PluginFile.GetFileNameWithoutExtension(), RawObject); // 添加到缓存
						}

						// 验证所有GameFeaturePlugins默认禁用
						// 如果EnabledByDefault为true且插件被禁用，名称将嵌入到可执行文件中
						// 如果这是个问题，启用此警告并更改游戏功能编辑器插件模板，为新插件禁用EnabledByDefault
						bool bEnabledByDefault = false; // 初始化默认启用标志
						if (!RawObject.TryGetBoolField("EnabledByDefault", out bEnabledByDefault) || bEnabledByDefault == true) // 如果未设置或为true
						{
							//Log.TraceWarning("GameFeaturePlugin {0}, does not set EnabledByDefault to false. This is required for built-in GameFeaturePlugins.", PluginFile.GetFileNameWithoutExtension());
						}

						// 验证所有GameFeaturePlugins设置为显式加载
						// 这很重要，因为游戏功能插件期望在项目启动后加载
						bool bExplicitlyLoaded = false; // 初始化显式加载标志
						if (!RawObject.TryGetBoolField("ExplicitlyLoaded", out bExplicitlyLoaded) || bExplicitlyLoaded == false) // 如果未设置或为false
						{
							Logger.LogWarning("GameFeaturePlugin {0}, does not set ExplicitlyLoaded to true. This is required for GameFeaturePlugins.", PluginFile.GetFileNameWithoutExtension()); // 记录警告
						}

						// 您可以在此处读取项目特定的额外字段，例如，
						//string PluginReleaseVersion;
						//if (RawObject.TryGetStringField("MyProjectReleaseVersion", out PluginReleaseVersion))
						//{
						//		bEnabled = SomeFunctionOf(PluginReleaseVersion, CurrentReleaseVersion) || bBuildAllGameFeaturePlugins;
						//}

						if (bBuildAllGameFeaturePlugins) // 如果要构建所有游戏功能插件
						{
							// 我们处于需要所有游戏功能插件的模式，除了那些无法加载或编译的
							bEnabled = true; // 启用插件
						}

						// 防止在非编辑器构建中使用仅编辑器功能插件
						bool bEditorOnly = false; // 初始化仅编辑器标志
						if (RawObject.TryGetBoolField("EditorOnly", out bEditorOnly)) // 如果存在EditorOnly字段
						{
							if (bEditorOnly && (Target.Type != TargetType.Editor) && !bBuildAllGameFeaturePlugins) // 如果是仅编辑器且目标不是编辑器，且不构建所有插件
							{
								// 插件是仅编辑器的，我们正在构建非编辑器目标，因此禁用它
								bForceDisabled = true; // 强制禁用
							}
						}
						else
						{
							// EditorOnly是可选的
						}

						// 一些插件应仅在特定分支中可用
						string RestrictToBranch; // 声明限制分支字符串
						if (RawObject.TryGetStringField("RestrictToBranch", out RestrictToBranch)) // 如果存在RestrictToBranch字段
						{
							if (!Target.Version.BranchName.Equals(RestrictToBranch, StringComparison.OrdinalIgnoreCase)) // 如果当前分支不匹配限制分支
							{
								// 插件用于特定分支，而当前不是
								bForceDisabled = true; // 强制禁用
								Logger.LogDebug("GameFeaturePlugin {Name} was marked as restricted to other branches. Disabling.", PluginFile.GetFileNameWithoutExtension()); // 记录调试信息
							}
							else
							{
								Logger.LogDebug("GameFeaturePlugin {Name} was marked as restricted to this branch. Leaving enabled.", PluginFile.GetFileNameWithoutExtension()); // 记录调试信息
							}
						}

						// 插件可以标记为NeverBuild，这会覆盖上述设置
						bool bNeverBuild = false; // 初始化永不构建标志
						if (RawObject.TryGetBoolField("NeverBuild", out bNeverBuild) && bNeverBuild) // 如果存在NeverBuild字段且为true
						{
							// 此插件被标记为永不编译，因此不要编译
							bForceDisabled = true; // 强制禁用
							Logger.LogDebug("GameFeaturePlugin {Name} was marked as NeverBuild, disabling.", PluginFile.GetFileNameWithoutExtension()); // 记录调试信息
						}

						// 跟踪插件引用以供后续验证
						JsonObject[] PluginReferencesArray; // 声明插件引用数组
						if (RawObject.TryGetObjectArrayField("Plugins", out PluginReferencesArray)) // 如果存在Plugins字段
						{
							foreach (JsonObject ReferenceObject in PluginReferencesArray) // 遍历每个引用对象
							{
								bool bRefEnabled = false; // 初始化引用启用标志
								if (ReferenceObject.TryGetBoolField("Enabled", out bRefEnabled) && bRefEnabled == true) // 如果引用启用且为true
								{
									string PluginReferenceName; // 声明插件引用名称
									if (ReferenceObject.TryGetStringField("Name", out PluginReferenceName)) // 如果存在Name字段
									{
										string ReferencerName = PluginFile.GetFileNameWithoutExtension(); // 获取引用者名称
										if (!AllPluginReferencesByName.ContainsKey(ReferencerName)) // 如果字典中不存在引用者
										{
											AllPluginReferencesByName[ReferencerName] = new List<string>(); // 创建新列表
										}
										AllPluginReferencesByName[ReferencerName].Add(PluginReferenceName); // 添加引用名称
									}
								}
							}
						}
					}
					catch (Exception ParseException) // 捕获解析异常
					{
						Logger.LogWarning("Failed to parse GameFeaturePlugin file {Name}, disabling. Exception: {1}", PluginFile.GetFileNameWithoutExtension(), ParseException.Message); // 记录警告
						bForceDisabled = true; // 强制禁用
					}

					// 禁用优先于启用
					if (bForceDisabled) // 如果强制禁用
					{
						bEnabled = false; // 设置为不启用
					}

					// 打印此插件的最终决定
					Logger.LogDebug("ConfigureGameFeaturePlugins() has decided to {Action} feature {Name}", bEnabled ? "enable" : (bForceDisabled ? "disable" : "ignore"), PluginFile.GetFileNameWithoutExtension()); // 记录调试信息

					// 启用或禁用它
					if (bEnabled) // 如果启用
					{
						Target.EnablePlugins.Add(PluginFile.GetFileNameWithoutExtension()); // 添加到启用插件列表
					}
					else if (bForceDisabled) // 如果强制禁用
					{
						Target.DisablePlugins.Add(PluginFile.GetFileNameWithoutExtension()); // 添加到禁用插件列表
					}
				}
			}

			// 如果您使用类似发布版本的东西，考虑进行引用验证以确保
			// 具有较早发布版本的插件不依赖于具有较晚发布版本的内容
		}
	}
}